﻿using Elasticsearch.Net;
using Microsoft.Extensions.Configuration;
using Nest;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using VisionCloud.Utility;
using VisionCloud.Utility.Security;

namespace VisionCloud.Service.ElasticSearch
{
    /// <summary>
    /// surface日志服务
    /// </summary>
    public class SurfaceLogEsService
    {
        private readonly IElasticClient elasticClient;
        private readonly IConnectionPool pool;
        private readonly IConfiguration cfg;

        public SurfaceLogEsService(IElasticClient elasticClient, IConnectionPool pool, IConfiguration cfg)
        {
            this.elasticClient = elasticClient;
            this.pool = pool;
            this.cfg = cfg;
        }

        /// <summary>
        /// 根据日期返回index
        /// </summary>
        public static string GetIndex() => $"surfaceserver-{DateTime.Now.ToString("yyyy.MM.dd")}";

        /// <summary>
        /// 根据泛型类创建对应的索引
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="index"></param>
        /// <returns></returns>
        public bool CeateIndex<T>(string index) where T : class, new()
        {
            if (string.IsNullOrEmpty(index))

                throw new Exception("YB0047".SLocalize());

            if (ExistsIndex(index))
                return true;

            var result = elasticClient.Indices.Create(index, p => p.Map<T>(m => m.AutoMap()));
            return result.ShardsAcknowledged;
        }

        /// <summary>
        /// 查询某个索引是否存在
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public bool ExistsIndex(string index)
        {
            if (string.IsNullOrEmpty(index))
                return false;
            var result = elasticClient.Indices.Exists(index);
            return result.Exists;
        }

        /// <summary>
        /// 初始化index
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="index"></param>
        /// <returns></returns>
        public bool InitIndex<T>(string index) where T : class, new()
        {
            if (ExistsIndex(index))
                return true;

            return CeateIndex<T>(index);
        }

        private static ElasticClient DefaultClient;
        /// <summary>
        /// 获取全局静态的ElasticClient
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private ElasticClient GetElasticClient(string index)
        {
            if (DefaultClient != null && DefaultClient.ConnectionSettings.DefaultIndex == index)
                return DefaultClient;

            var setting = new ConnectionSettings(pool).BasicAuthentication(AesCoreHelper.Decrypt(cfg["NLog:UserName"], AesCoreHelper.Sceret),
                AesCoreHelper.Decrypt(cfg["NLog:PassWord"], AesCoreHelper.Sceret)).DefaultIndex(index);

            DefaultClient = new ElasticClient(setting);

            return DefaultClient;
        }

        /// <summary>
        /// 写入日志
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="index"></param>
        public async ValueTask<bool> WriteLog<T>(T dto, string index) where T : class, new()
        {
            var initSucc = InitIndex<T>(index);
            if (!initSucc)
                return initSucc;

            var client = GetElasticClient(index);
            var result = await client.IndexDocumentAsync(dto);
            return result.IsValid;
        }

        /// <summary>
        /// 获取日志列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="index"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        public IEnumerable<T> GetList<T>(string index, int pageIndex, int pageSize, Func<QueryContainerDescriptor<T>, QueryContainer> query = null, Func<SortDescriptor<T>, IPromise<IList<ISort>>> sort = null) where T : class, new()
        {
            if (string.IsNullOrEmpty(index))
                throw new ArgumentNullException("YB0047".SLocalize());
            var start = Math.Max(pageIndex - 1, 0) * pageSize;
            ISearchResponse<T> list;
            if (query == null)
                query = p => p.MatchAll();
            if (sort == null)
            {
                list = elasticClient.Search<T>(p => p.Index(index).Query(query).Skip(start).Take(pageSize));
            }
            else
            {
                list = elasticClient.Search<T>(p => p.Index(index).Query(query).Sort(sort).Skip(start).Take(pageSize));
            }

            return list.Documents;
        }

        /// <summary>
        /// 获取日志列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="selector"></param>
        /// <returns></returns>
        public IEnumerable<T> GetList<T>(Func<SearchDescriptor<T>, ISearchRequest> selector = null) where T : class, new()
        {
            var list = elasticClient.Search<T>(selector);
            return list.Documents;
        }
    }
}